package 链表.环形列表plus;
/**
 * 题目描述
 * 给定一个链表的头节点  head ，返回链表开始入环的第一个节点。 如果链表无环，则返回 null。
 * 如果链表中有某个节点，可以通过连续跟踪 next 指针再次到达，则链表中存在环。
 * 为了表示给定链表中的环，评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置（索引从 0 开始）。
 * 如果 pos 是 -1，则在该链表中没有环。注意：pos 不作为参数进行传递，仅仅是为了标识链表的实际情况。
 * 不允许修改 链表。
 * 力扣：https://leetcode-cn.com/problems/linked-list-cycle-ii/
 * 力扣第142题
 * 输入：head = [3,2,0,-4], pos = 1
 * 输出：返回索引为 1 的链表节点
 * 解释：链表中有一个环，其尾部连接到第二个节点。
 * */
/**
 *解题思路：
 * 假设从头结点到环形入口节点 的节点数为x。
 * 环形入口节点到 fast指针与slow指针相遇节点 节点数为y。
 * 从相遇节点 再到环形入口节点节点数为 z。
 * 那么相遇时：
 * slow指针走过的节点数为: x + y
 * fast指针走过的节点数： x + y + n (y + z)，n为fast指针在环内走了n圈才遇到slow指针， （y+z）为 一圈内节点的个数
 * 因为fast指针是一步走两个节点，slow指针一步走一个节点， 所以 fast指针走过的节点数 = slow指针走过的节点数 * 2
 * (x + y) * 2 = x + y + n (y + z)
 * 两边消掉一个（x+y）: x + y = n (y + z)
 * 因为我们要找环形的入口，那么要求的是x，因为x表示 头结点到 环形入口节点的的距离。
 * 所以我们要求x ，将x单独放在左面：x = n (y + z) - y
 * 在从n(y+z)中提出一个 （y+z）来，整理公式之后为如下公式：x = (n - 1) (y + z) + z
 * 注意这里n一定是大于等于1的，因为 fast指针至少要多走一圈才能相遇slow指针
 * 这个公式说明什么呢，
 * 先拿n为1的情况来举例，意味着fast指针在环形里转了一圈之后，就遇到了 slow指针了。
 * 当 n为1的时候，公式就化解为 x = z
 * 重要：这就意味着，从头结点出发一个指针，从相遇节点 也出发一个指针，这两个指针每次只走一个节点，
 * 那么当这两个指针相遇的时候就是 环形入口的节点
 * 也就是在相遇节点处，定义一个指针index1，在头结点处定一个指针index2。
 * 让index1和index2同时移动，每次移动一个节点， 那么他们相遇的地方就是 环形入口的节点。
 * 那么 n如果大于1是什么情况呢，就是fast指针在环形转n圈之后才遇到 slow指针。
 * 其实这种情况和n为1的时候 效果是一样的，一样可以通过这个方法找到 环形的入口节点，
 * 只不过，index1 指针在环里 多转了(n-1)圈，然后再遇到index2，相遇点依然是环形的入口节点。
 * */
/**
 *为什么第一次在环中相遇，slow的 步数 是 x+y 而不是 x + 若干环的长度 + y 呢？
 * 因为快指针走完一圈后，慢指针换没有走完一圈，这样就会相遇所以是x+y
 * */

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {// 有环
                ListNode index1 = fast;
                ListNode index2 = head;
                // 两个指针，从头结点和相遇结点，各走一步，直到相遇，相遇点即为环入口
                while (index1 != index2) {
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }
        return null;
    }
}